<template>
  <div
    :class="
      Number(props.class) == 1
        ? 'font-bg-gradient1'
        : Number(props.class) == 2
        ? 'font-bg-gradient2'
        : Number(props.class) == 3
        ? 'font-bg-color'
        : Number(props.class) == 10
        ? 'font-bg-gradient10'
        : 'font-bg-color-child'
    "
    :style="`color:${props.color};`"
  >
    {{ state.displayValue }}{{props.unit}}<span v-if="props.old > 0"> ({{ props.old }})</span>
  </div>
</template>
<script lang="ts" setup>
// vue3.2新的语法糖, 编写代码更加简洁高效
import { onMounted, onUnmounted, reactive } from '@vue/runtime-core'
import { watch, computed } from 'vue'
import {
  requestAnimationFrame,
  cancelAnimationFrame
} from '../../util/requestAnimationFrame'
// 定义父组件传递的参数
const props: any = defineProps({
  color:{
    type: String,
    required: false,
    default: '#ffffff'
  },
  unit:{
    type: String,
    required: false,
    default: ''
  },
  start: {
    type: Number,
    required: false,
    default: 0
  },
  end: {
    type: Number,
    required: false,
    default: 0
  },
  duration: {
    type: Number,
    required: false,
    default: 5000
  },
  autoPlay: {
    type: Boolean,
    required: false,
    default: true
  },
  class: {
    type: String,
    required: false,
    default: '1'
  },
  old: {
    type: Number,
    required: false,
    default: 0
  },
  decimals: {
    type: Number,
    required: false,
    default: 2,
    validator (value: number) {
      return value >= 0
    }
  },
  decimal: {
    type: String,
    required: false,
    default: '.'
  },
  separator: {
    type: String,
    required: false,
    default: ''
  },
  prefix: {
    type: String,
    required: false,
    default: ''
  },
  suffix: {
    type: String,
    required: false,
    default: ''
  },
  useEasing: {
    type: Boolean,
    required: false,
    default: true
  },
  default: {
    type: Number,
    required: false,
    default: 0
  },
  easingFn: {
    type: Function,
    default (t: any, b: any, c: any, d: any) {
      return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b
    }
  }
})
const isNumber = (val: any) => {
  return !isNaN(parseFloat(val))
}
// 格式化数据，返回想要展示的数据格式
const formatNumber = (val: any) => {
  // 使用props.decimals而不是props.default来保留小数
  val = Number(val).toFixed(props.decimals)
  val += ''
  const x = val.split('.')
  let x1 = x[0]
  const x2 = x.length > 1 ? props.decimal + x[1] : ''
  const rgx = /(\d+)(\d{3})/
  if (props.separator && !isNumber(props.separator)) {
    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    }
  }
  return props.prefix + x1 + x2 + props.suffix
}
// 相当于vue2中的data中所定义的变量部分
const state = reactive<any>({
  localStart: props.start,
  displayValue: props.start,
  printVal: null,
  paused: false,
  localDuration: props.duration,
  startTime: null,
  timestamp: null,
  remaining: null,
  rAF: null
})
// 定义一个计算属性，当开始数字大于结束数字时返回true
const stopCount = computed(() => {
  return props.start > props.end
})
// 定义父组件的自定义事件，子组件以触发父组件的自定义事件
const emits = defineEmits(['onMountedcallback', 'callback'])
const startCount = () => {
  state.localStart = props.start
  state.startTime = null
  state.localDuration = props.duration
  state.paused = false
  state.rAF = requestAnimationFrame(count)
}
watch(
  () => props.start,
  () => {
    if (props.autoPlay) {
      startCount()
    }
  }
)
watch(
  () => props.end,
  () => {
    if (props.autoPlay) {
      startCount()
    }
  }
)
// dom挂在完成后执行一些操作
onMounted(() => {
  if (props.autoPlay) {
    startCount()
  }
  emits('onMountedcallback')
})
// 暂停计数
//   const pause = () => {
//     cancelAnimationFrame(state.rAF)
//   }
// 恢复计数
//   const resume = () => {
//     state.startTime = null
//     state.localDuration = +state.remaining
//     state.localStart = +state.printVal
//     requestAnimationFrame(count)
//   }
//   const pauseResume = () => {
//     if (state.paused) {
//       resume()
//       state.paused = false
//     } else {
//       pause()
//       state.paused = true
//     }
//   }
//   const reset = () => {
//     state.startTime = null
//     cancelAnimationFrame(state.rAF)
//     state.displayValue = formatNumber(props.start)
//   }
const count = (timestamp: any) => {
  if (!state.startTime) state.startTime = timestamp
  state.timestamp = timestamp
  const progress = timestamp - state.startTime
  state.remaining = state.localDuration - progress
  // 是否使用速度变化曲线
  if (props.useEasing) {
    if (stopCount.value) {
      state.printVal =
        state.localStart -
        props.easingFn(
          progress,
          0,
          state.localStart - props.end,
          state.localDuration
        )
    } else {
      state.printVal = props.easingFn(
        progress,
        state.localStart,
        props.end - state.localStart,
        state.localDuration
      )
    }
  } else {
    if (stopCount.value) {
      state.printVal =
        state.localStart -
        (state.localStart - props.end) * (progress / state.localDuration)
    } else {
      state.printVal =
        state.localStart +
        (props.end - state.localStart) * (progress / state.localDuration)
    }
  }
  if (stopCount.value) {
    state.printVal = state.printVal < props.end ? props.end : state.printVal
  } else {
    state.printVal = state.printVal > props.end ? props.end : state.printVal
  }
  state.displayValue = formatNumber(state.printVal)
  if (progress < state.localDuration) {
    state.rAF = requestAnimationFrame(count)
  } else {
    emits('callback')
  }
}
// 组件销毁时取消动画
onUnmounted(() => {
  cancelAnimationFrame(state.rAF)
})
</script>
<style lang="scss" scoped>
.font-bg-gradient1 {
  color: #5bd0fe;
  font-size: 40px!important;
  background-image: -webkit-linear-gradient(bottom, #00a1fa, #42c3fd, #67d6ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: bold;
}
.font-bg-gradient2 {
  font-family: Arial, Helvetica, sans-serif;
  color: #62fdc5;
  font-weight: bold;
  font-size: 40px!important;
  background-image: -webkit-linear-gradient(bottom, #3efb97, #62fdc5, #7affe3);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  padding: 0 !important;
}
.font-bg-gradient10 {
  font-family: Arial, Helvetica, sans-serif;
  color: #F5B915;
  font-weight: bold;
  font-size: 40px!important;
  background-image: -webkit-linear-gradient(bottom, #F5B915, #F5B915, #FFF3A2);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  padding: 0 !important;
}
.font-bg-color {
  color: var(--el-text-color-regular);
  font-size: 20px;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: bold;
}
.font-bg-color-child {
  color: var(--el-text-color-regular);
  font-weight: bold;
  font-size:18px;
  font-family: Arial, Helvetica, sans-serif;
}
</style>
